import base64
import json

from Crypto.Hash import SHA1, SHA256
from Crypto.PublicKey import RSA
from Crypto.Signature import pkcs1_15
from Crypto.Util.asn1 import DerSequence, DerObjectId, DerNull, DerOctetString
from Crypto.Util.number import ceil_div
from cryptography import x509
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import padding

# 插件路径
ja_netfilter_path = r'C:\Users\Public\.ja-netfilter'
# 公钥路径
public_key_path = f'{ja_netfilter_path}\\ca.crt'
# 私钥路径
private_key_path = f'{ja_netfilter_path}\\ca.key'


# noinspection PyTypeChecker
def pkcs15_encode(msg_hash, em_len, with_hash_parameters=True):
    """
    Implement the ``EMSA-PKCS1-V1_5-ENCODE`` function, as defined
    :param msg_hash: hash object
    :param em_len: int
    :param with_hash_parameters: bool
    :return: An ``emLen`` byte long string that encodes the hash.
    """
    digest_algo = DerSequence([DerObjectId(msg_hash.oid).encode()])

    if with_hash_parameters:
        digest_algo.append(DerNull().encode())

    digest = DerOctetString(msg_hash.digest())
    digest_info = DerSequence([
        digest_algo.encode(),
        digest.encode()
    ]).encode()

    # We need at least 11 bytes for the remaining data: 3 fixed bytes and
    # at least 8 bytes of padding.
    if em_len < len(digest_info) + 11:
        raise TypeError("Selected hash algorithm has a too long digest (%d bytes)." % len(digest))
    ps = b'\xFF' * (em_len - len(digest_info) - 3)
    return b'\x00\x01' + ps + b'\x00' + digest_info


def read_public_key():
    # 读取公钥
    with open(public_key_path, 'r') as file:
        cert_content = file.read()
    cert_base64 = (cert_content.replace('-----BEGIN CERTIFICATE-----', '')
                   .replace('-----END CERTIFICATE-----', '')
                   .replace('\n', '')
                   .strip())
    return cert_base64


def read_private_key():
    with open(private_key_path) as file:
        cert_content = file.read()
    return cert_content


def generate_sign_code(public_key_base64):
    cert = x509.load_der_x509_certificate(base64.b64decode(public_key_base64))
    public_key = cert.public_key()
    sign = int.from_bytes(cert.signature, byteorder="big", )

    mod_bits = public_key.key_size
    digest_cert = SHA256.new(cert.tbs_certificate_bytes)
    result = int.from_bytes(pkcs15_encode(digest_cert, ceil_div(mod_bits, 8)), byteorder='big', signed=False)

    pub_key = '860106576952879101192782278876319243486072481962999610484027161162448933268423045647258145695082284265933019120714643752088997312766689988016808929265129401027490891810902278465065056686129972085119605237470899952751915070244375173428976413406363879128531449407795115913715863867259163957682164040613505040314747660800424242248055421184038777878268502955477482203711835548014501087778959157112423823275878824729132393281517778742463067583320091009916141454657614089600126948087954465055321987012989937065785013284988096504657892738536613208311013047138019418152103262155848541574327484510025594166239784429845180875774012229784878903603491426732347994359380330103328705981064044872334790365894924494923595382470094461546336020961505275530597716457288511366082299255537762891238136381924520749228412559219346777184174219999640906007205260040707839706131662149325151230558316068068139406816080119906833578907759960298749494098180107991752250725928647349597506532778539709852254478061194098069801549845163358315116260915270480057699929968468068015735162890213859113563672040630687357054902747438421559817252127187138838514773245413540030800888215961904267348727206110582505606182944023582459006406137831940959195566364811905585377246353'
    sign_code = f'EQUAL,{sign},65537,{pub_key}->{result}'
    return sign_code


def generate_key(public_key_base64, license_json):
    private_key = read_private_key()
    license_id = license_json.get('licenseId')
    license_part = json.dumps(license_json)
    digest = SHA1.new(license_part.encode('utf-8'))
    ca_suffix = '-MIIETDCCAjSgAwIBAgIBDTANBgkqhkiG9w0BAQsFADAYMRYwFAYDVQQDDA1KZXRQcm9maWxlIENBMB4XDTIwMTAxOTA5MDU1M1oXDTIyMTAyMTA5MDU1M1owHzEdMBsGA1UEAwwUcHJvZDJ5LWZyb20tMjAyMDEwMTkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCUlaUFc1wf+CfY9wzFWEL2euKQ5nswqb57V8QZG7d7RoR6rwYUIXseTOAFq210oMEe++LCjzKDuqwDfsyhgDNTgZBPAaC4vUU2oy+XR+Fq8nBixWIsH668HeOnRK6RRhsr0rJzRB95aZ3EAPzBuQ2qPaNGm17pAX0Rd6MPRgjp75IWwI9eA6aMEdPQEVN7uyOtM5zSsjoj79Lbu1fjShOnQZuJcsV8tqnayeFkNzv2LTOlofU/Tbx502Ro073gGjoeRzNvrynAP03pL486P3KCAyiNPhDs2z8/COMrxRlZW5mfzo0xsK0dQGNH3UoG/9RVwHG4eS8LFpMTR9oetHZBAgMBAAGjgZkwgZYwCQYDVR0TBAIwADAdBgNVHQ4EFgQUJNoRIpb1hUHAk0foMSNM9MCEAv8wSAYDVR0jBEEwP4AUo562SGdCEjZBvW3gubSgUouX8bOhHKQaMBgxFjAUBgNVBAMMDUpldFByb2ZpbGUgQ0GCCQDSbLGDsoN54TATBgNVHSUEDDAKBggrBgEFBQcDATALBgNVHQ8EBAMCBaAwDQYJKoZIhvcNAQELBQADggIBABqRoNGxAQct9dQUFK8xqhiZaYPd30TlmCmSAaGJ0eBpvkVeqA2jGYhAQRqFiAlFC63JKvWvRZO1iRuWCEfUMkdqQ9VQPXziE/BlsOIgrL6RlJfuFcEZ8TK3syIfIGQZNCxYhLLUuet2HE6LJYPQ5c0jH4kDooRpcVZ4rBxNwddpctUO2te9UU5/FjhioZQsPvd92qOTsV+8Cyl2fvNhNKD1Uu9ff5AkVIQn4JU23ozdB/R5oUlebwaTE6WZNBs+TA/qPj+5/we9NH71WRB0hqUoLI2AKKyiPw++FtN4Su1vsdDlrAzDj9ILjpjJKA1ImuVcG329/WTYIKysZ1CWK3zATg9BeCUPAV1pQy8ToXOq+RSYen6winZ2OO93eyHv2Iw5kbn1dqfBw1BuTE29V2FJKicJSu8iEOpfoafwJISXmz1wnnWL3V/0NxTulfWsXugOoLfv0ZIBP1xH9kmf22jjQ2JiHhQZP7ZDsreRrOeIQ/c4yR8IQvMLfC0WKQqrHu5ZzXTH4NO3CwGWSlTY74kE91zXB5mwWAx1jig+UXYc2w4RkVhy0//lOmVya/PEepuuTTI4+UJwC7qbVlh5zfhj8oTNUXgN0AOc+Q0/WFPl1aw5VV/VrO8FCoB15lFVlpKaQ1Yh+DVU8ke+rt9Th0BCHXe0uZOEmH0nOnH/0onD'
    private_key = RSA.import_key(private_key)
    # 使用私钥对HASH值进行签名
    signature = pkcs1_15.new(private_key).sign(digest)

    sig_results = base64.b64encode(signature)
    license_part_base64 = base64.b64encode(bytes(license_part.encode('utf-8')))
    cert = x509.load_der_x509_certificate(base64.b64decode(public_key_base64))
    public_key = cert.public_key()
    public_key.verify(
        base64.b64decode(sig_results),
        base64.b64decode(license_part_base64),
        padding=padding.PKCS1v15(),
        algorithm=hashes.SHA1(),
    )
    license_code = license_id + "-" + license_part_base64.decode('utf-8') + "-" + sig_results.decode('utf-8') + "-" + public_key_base64 + ca_suffix
    return license_code
